package com.yunquan.ohana.utils

import android.annotation.SuppressLint
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.TimeZone
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.YearMonth
import java.time.ZoneId
import java.time.temporal.TemporalAdjusters

/**
 * 日期时间操作工具$
 *
 * @author yjp
 * @date 2020-03-29 15:24
 */
@SuppressLint("SimpleDateFormat")
object DateUtils {
    /**
     * 中文星期
     */
    val WEEK_CN = arrayOf("星期天", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六")

    /**
     * 英文星期
     */
    val WEEK_EN =
        arrayOf("SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY")

    /**
     * 当前年
     */
    val YEAR by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { LocalDate.now().year }

    /**
     * 当前月
     */
    val MONTH by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { LocalDate.now().monthValue }

    /**
     * 当前天
     */
    val DAY by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { LocalDate.now().dayOfMonth }

    /**
     * 当前小时
     */
    val HOUR by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { LocalDateTime.now().hour }

    /**
     * 当前分
     */
    val MIN by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { LocalDateTime.now().minute }

    /**
     * 当前秒
     */
    val SEC by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { LocalDateTime.now().second }

    /**
     * 星期
     */
    val WEEK by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { WEEK_CN[WEEK_INDEX] }

    /**
     * 星期下标
     */
    val WEEK_INDEX by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
        // LocalDate.dayOfWeek.value: Monday=1..Sunday=7; map Sunday->0, Monday->1..Saturday->6
        val v = LocalDate.now().dayOfWeek.value
        v % 7
    }

    fun now(): String {
        return date2Str(System.currentTimeMillis())
    }

    fun now(format: String): String {
        return date2Str(System.currentTimeMillis(), format)
    }

    fun nowToDate(): Date {
        return Date(System.currentTimeMillis())
    }

    /**
     * 日期转字符串
     */
    fun date2Str(date: Any): String {
        return date2Str(date, FORMAT.DATETIME_HORIZONTAL)
    }

    /**
     * 日期转字符串
     */
    fun date2Str(date: Any, format: String): String {
        val sdf = SimpleDateFormat(format)
        return when (date) {
            is Date -> {
                sdf.format(date)
            }

            is Long -> {
                sdf.format(Date(date))
            }

            else -> {
                throw RuntimeException("传入日期有误，仅支持 Date 或 Long 类型")
            }
        }
    }

    /**
     * 字符串转日期
     */
    fun str2Date(date: String): Date {
        return str2Date(date, FORMAT.DATETIME_HORIZONTAL)
    }

    /**
     * 字符串转日期
     */
    fun str2Date(date: String, format: String): Date {
        val sdf = SimpleDateFormat(format)
        return sdf.parse(date)!!
    }

    /**
     * 转化时间输入时间与当前时间的间隔
     */
    fun converTime(timestamp: Long): String {
        var currentSeconds = System.currentTimeMillis() / 1000
        var timeGap = currentSeconds - timestamp;
        return when {
            timeGap > 24 * 60 * 60 -> {
                (timeGap / (24 * 60 * 60)).toString() + "天前"
            }

            timeGap > 60 * 60 -> {
                (timeGap / (60 * 60)).toString() + "小时前"
            }

            timeGap > 60 -> {
                (timeGap / 60).toString() + "分钟前"
            }

            else -> {
                "刚刚"
            }
        }
    }

    /**
     * 日期加减处理
     *
     * @param date   原日期
     * @param field  加减单位
     * @param amount 加减数量
     * @return
     */
    fun add(date: Any, field: Int, amount: Int): Date {
        val zone = ZoneId.systemDefault()
        val baseDate: Date = when (date) {
            is Date -> date
            is String -> str2Date(date)
            is Long -> Date(date)
            else -> return Date()
        }
        val baseLdt = LocalDateTime.ofInstant(baseDate.toInstant(), zone)
        val adjusted = when (field) {
            java.util.Calendar.YEAR -> baseLdt.plusYears(amount.toLong())
            java.util.Calendar.MONTH -> baseLdt.plusMonths(amount.toLong())
            java.util.Calendar.WEEK_OF_YEAR, java.util.Calendar.WEEK_OF_MONTH -> baseLdt.plusWeeks(amount.toLong())
            java.util.Calendar.DAY_OF_MONTH, java.util.Calendar.DATE -> baseLdt.plusDays(amount.toLong())
            java.util.Calendar.HOUR_OF_DAY, java.util.Calendar.HOUR -> baseLdt.plusHours(amount.toLong())
            java.util.Calendar.MINUTE -> baseLdt.plusMinutes(amount.toLong())
            java.util.Calendar.SECOND -> baseLdt.plusSeconds(amount.toLong())
            java.util.Calendar.MILLISECOND -> baseLdt.plusNanos(amount.toLong() * 1_000_000)
            else -> baseLdt
        }
        return Date.from(adjusted.atZone(zone).toInstant())
    }

    /**
     * 判断原日期是否在目标日期之前
     */
    fun isBefore(src: Date, dst: Date): Boolean {
        return src.before(dst)
    }

    /**
     * 判断原日期是否在目标日期之后
     */
    fun isAfter(src: Date, dst: Date): Boolean {
        return src.after(dst)
    }

    /**
     * 判断两日期是否相同
     */
    fun isEqual(src: Date, dst: Date): Boolean {
        return src.compareTo(dst) == 0
    }

    /**
     * 判断某个日期是否在某个日期范围
     */
    fun between(beginDate: Date, endDate: Date, src: Date): Boolean {
        return beginDate.before(src) && endDate.after(src)
    }

    /**
     * 比较时间大小
     * 1:小于 -2:大于 0:等于
     */
    fun compareDate(begin: String, end: String): Int {
        val df = SimpleDateFormat(FORMAT.DATETIME_YMDHM)
        try {
            val beginDate = df.parse(begin)
            val endDate = df.parse(end)
            return when {
                beginDate!!.time < endDate!!.time -> {
                    1
                }

                beginDate.time > endDate.time -> {
                    -1
                }

                else -> {
                    0
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return 0
    }

    /**
     * 获取天数差
     */
    fun dayDiff(begin: Date, end: Date): Long {
        return when {
            end.time < begin.time -> {
                -1
            }

            end.time == begin.time -> {
                1
            }

            else -> {
                ((end.time - begin.time) / (24 * 60 * 60 * 1000)) + 1
            }
        }
    }

    /**
     * 获取传入的日期所在周的开始与结束日期
     * 日历模式
     */
    fun getWeekRange(dateTime: LocalDateTime): Pair<LocalDateTime, LocalDateTime> {
        // 当前是星期几（1=Mon ... 7=Sun）
        val dayOfWeek = dateTime.dayOfWeek.value

        // 计算距离周日要回退的天数
        val daysToSubtract = if (dayOfWeek == 7) 0 else dayOfWeek
        val startOfWeek = dateTime
            .minusDays(daysToSubtract.toLong())
            .withHour(0).withMinute(0).withSecond(0).withNano(0)

        // 计算距离周六要前进的天数
        val daysToAdd = if (dayOfWeek == 6) 0 else (6 - dayOfWeek + 7) % 7
        val endOfWeek = dateTime
            .plusDays(daysToAdd.toLong())
            .withHour(23).withMinute(59).withSecond(59).withNano(0)

        return startOfWeek to endOfWeek
    }

    /**
     * 获取传入的日期所在月的开始与结束日期
     * 日历模式
     */
    fun getMonthRange(dateTime: LocalDateTime): Pair<LocalDateTime, LocalDateTime> {
        // 当月第一天 00:00:00
        val firstDayOfMonth = dateTime
            .with(TemporalAdjusters.firstDayOfMonth())
            .withHour(0).withMinute(0).withSecond(0).withNano(0)

        // 当月最后一天 23:59:59
        val lastDayOfMonth = dateTime
            .with(TemporalAdjusters.lastDayOfMonth())
            .withHour(23).withMinute(59).withSecond(59).withNano(0)

        // 计算起始周日
        val firstDayOfWeek = firstDayOfMonth.dayOfWeek.value // 1=Mon ... 7=Sun
        val daysToSubtract = if (firstDayOfWeek == 7) 0 else firstDayOfWeek
        val startOfCalendar = firstDayOfMonth.minusDays(daysToSubtract.toLong())

        // 计算结束周六
        val endDayOfWeek = lastDayOfMonth.dayOfWeek.value
        val daysToAdd = if (endDayOfWeek == 6) 0 else (6 - endDayOfWeek + 7) % 7
        val endOfCalendar = lastDayOfMonth.plusDays(daysToAdd.toLong())

        return startOfCalendar to endOfCalendar
    }

    /**
     * 获取月的最后一天
     */
    fun lastDayOfMonth(date: Date): Date {
        val zone = ZoneId.systemDefault()
        val ld = date.toInstant().atZone(zone).toLocalDate()
        val endOfMonth = YearMonth.from(ld).atEndOfMonth().atTime(23, 59, 59, 999_000_000)
        return Date.from(endOfMonth.atZone(zone).toInstant())
    }

    /**
     * 获取月的第一天
     */
    fun firstDayOfMonth(date: Date): Date {
        val zone = ZoneId.systemDefault()
        val ld = date.toInstant().atZone(zone).toLocalDate()
        val startOfMonth = YearMonth.from(ld).atDay(1).atStartOfDay()
        return Date.from(startOfMonth.atZone(zone).toInstant())
    }

    /**
     * 获取传入的日期月份最大天数
     */
    fun getMonthMaxDay(date: Date): Int {
        val zone = ZoneId.systemDefault()
        val ld = date.toInstant().atZone(zone).toLocalDate()
        return YearMonth.from(ld).lengthOfMonth()
    }

    /**
     * 判断是否是平年
     * */
    fun isPingNian(year: Int): Boolean {
        return year % 4 == 0 && year % 100 != 0 || year % 400 == 0
    }

    /**
     * 毫秒转时间格式
     * 00:00:00
     */
    @SuppressLint("DefaultLocale")
    fun toTime(millis: Long, format: String): String {
        val sdf = SimpleDateFormat(format, Locale.getDefault())
        sdf.timeZone = TimeZone.getTimeZone("UTC") // 使用 UTC 时区保证格式正确
        return sdf.format(Date(millis))
    }

    /**
     * 定义日期的格式
     * */
    object FORMAT {
        const val DATETIME_TXT = "yyyy年MM月dd日 HH:mm:ss"
        const val DATETIME_YMDHM = "yyyy-MM-dd HH:mm"
        const val DATETIME_YMDH = "yyyy-MM-dd HH"
        const val YEAR_MONTH = "yyyy-MM"

        /**
         * 6位日期格式
         */
        const val DATE_6CHAR = "yyMMdd"

        /**
         * 8位日期格式
         */
        const val DATE_8CHAR = "yyyyMMdd"

        /**
         * 点号日期格式
         */
        const val DATE_DOT = "yyyy.MM.dd"

        /**
         * 反斜杠日期格式
         */
        const val DATE_SLASH = "yyyy/MM/dd"

        /**
         * 横杠日期格式
         */
        const val DATE_HORIZONTAL = "yyyy-MM-dd"

        /**
         * 日期时间(日期点号分割)
         */
        const val DATATIME_DOT = "yyyy.MM.dd HH:mm:ss"

        /**
         * 日期时间（文字分割）
         */
        const val DATATIME_TXT = "yyyy年MM月dd日 HH:mm"

        const val DATETXT = "yyyy年MM月dd日"

        const val DATE_TXT = "yyyy年MM月dd日 HH:mm:ss"

        /**
         * 日期时间(日期反斜杠)
         */
        const val DATETIME_SLASH = "yyyy/MM/dd HH:mm:ss"

        /**
         * 日期时间(日期横杠)
         */
        const val DATETIME_HORIZONTAL = "yyyy-MM-dd HH:mm:ss"
        const val HH_MM_A = "HH:mm a"
    }
}